#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <ctype.h>

struct tuple {
	int val;
	int idx;
};

/* {{{ mergesort */
static void
mergesort__merge(void *pbase, size_t nmemb, size_t size,
		int (*cmpf)(const void *, const void *),
		void *pcpybuf,
		size_t L, size_t M, size_t R)
{
	register char *base = (char *) pbase,
		      *cpybuf = (char *) pcpybuf;
	register size_t i = L,
			j = M + 1,
			s = 0; /* index
				  points to where we will place next element */

#ifdef D
	fprintf(stderr, "mergesort__merge(pbase==%p, nmemb==%zu, size==%zu, cmpf==%p, pcpybuf==%p, L==%zu, M==%zu, R==%zu)\n",
			pbase, nmemb, size, cmpf, pcpybuf, L, M, R);
#endif

	while (i <= M && j <= R) { //so this || was working great for almost a year… until now
#ifdef D
		fprintf(stderr, "mergesort__merge: calling (*cmpf)((void *) (base + i * size) == %016p, "
				"(void *) (base + j * size) == %016p) //i==%zu, j==%zu\n",
				(void *) (base + i * size), (void *) (base + j * size),
				i, j);
#endif
		if ((*cmpf)((void*) (base + i * size), (void*) (base + j * size)) <= 0) { //HOLD UP!.. nah nvm
			if (i <= M) {
				memcpy((void *) (cpybuf + s * size),
					(void *) (base + i * size), size);
				s++;
				i++;
			} else if (j <= R) {
				memcpy((void *) (cpybuf + s * size),
					(void *) (base + j * size), size);
				s++;
				j++;
			}
		} else {
			if (j <= R) {
				memcpy((void *) (cpybuf + s * size),
					(void *) (base + j * size), size);
				s++;
				j++;
			} else if (i <= M) {
				memcpy((void *) (cpybuf + s * size),
					(void *) (base + i * size), size);
				s++;
				i++;
			}
		}
	}

	/*
	 * let's see how this works
	 */
	while (i <= M)
		memcpy((void*) (cpybuf + (s++) * size),
			(void*) (base + (i++) * size), size);
	while (j <= R)
		memcpy((void*) (cpybuf + (s++) * size),
			(void*) (base + (j++) * size), size);

	for (i = 0; i < s; i++)
		memcpy((void *) (base + (L + i) * size),
				(void *) (cpybuf + i * size), size);
}

static void
mergesort__main(void *base, size_t nmemb, size_t size,
		int (*cmpf)(const void *, const void *),
		void *cpybuf,
		size_t L, size_t R)
{
	size_t M = (L + R) / 2;

	if (L < R) {
		mergesort__main(base, nmemb, size, cmpf, cpybuf, L, M);
		mergesort__main(base, nmemb, size, cmpf, cpybuf, M + 1, R);
		mergesort__merge(base, nmemb, size, cmpf, cpybuf, L, M, R);
	}
}

extern void
mergesort(void *base, size_t nmemb, size_t size,
		int (*cmpf)(const void *, const void *))
{
	void *cpybuf = NULL;

	cpybuf = malloc(nmemb * size + 1UL);
	mergesort__main(base, nmemb, size, cmpf, cpybuf,
			0UL, nmemb - 1UL);
	free(cpybuf);
}
/* }}} */

static int
cmp(const void *p1, const void *p2)
{
	return * (int *) p1 - * (int *) p2;
	/*
	 * This works because pointers to structs degrade to pointers to
	 * struct's first field, which is exactly what we need
	 */
}

int
main(int argc, char **argv)
{
	static struct tuple a[7001];
	int n, i;

	scanf("%d", &n);
	for (i = 0; i < n; i++) {
		scanf("%d", &a[i].val);
		a[i].idx = i;
	}
	mergesort(a, (size_t) n, sizeof a[0], cmp);
	for (i = 0; i < n; i++)
		printf("%d ", a[i].idx);
	fputc('\n', stdout);

	return 0;
}
